package jiggle.app;
import jiggle.*;

import java.awt.*; import java.awt.event.*;

public class SettingsDlg extends Dialog {
    // generated value for no structural changes
    private static final long serialVersionUID = 6797435304514575973L;

    JiggleFrame parent = null;

	Panel edgeLengthPanel = new Panel ();
	Label edgeLengthLabel = new Label ("Preferred Edge Length:");
	Slider edgeLength = new Slider(
	        Settings.prefEdgeLengthMin, 
	        Settings.prefEdgeLengthMax,
            Settings.prefEdgeLengthDefault);

	Panel sizePanel = new Panel ();
	Label vertexWidthLabel = new Label ("Vertex Width:");
	Slider vertexWidth = new Slider (Settings.vertexWidthMin, Settings.vertexWidthMax, Settings.vertexWidthDefault);
	Label vertexHeightLabel = new Label ("Vertex Height:");
	Slider vertexHeight = new Slider (Settings.vertexHeightMin, Settings.vertexHeightMax, Settings.vertexHeightDefault);
	Checkbox useVertexSize = new Checkbox ("Consider Vertex Size for Layout");

	Panel optimizationProcedurePanel1 = new Panel ();
	Label optimizationProcedureLabel = new Label ("Optimization Procedure:");
	CheckboxGroup optimizationProcedureGrp = new CheckboxGroup ();
	Checkbox steepestDescent = new Checkbox ("steepest descent");
	Checkbox conjugateGradients = new Checkbox ("conjugate gradients");

	Panel optimizationProcedurePanel2 = new Panel ();
	Label accuracyLabel = new Label ("Accuracy of Line Search:");
	Slider accuracyOfLineSearch = new Slider (1, 0, 0.5);
	Label restartLabel = new Label ("Restart Threshold for CG:");
	Slider restartThreshold = new Slider (0, 1, 0.2);

	Panel springPanel = new Panel ();
	Label springLabel = new Label ("Springs:");
	CheckboxGroup springLawGrp = new CheckboxGroup ();
	Checkbox linearSpring = new Checkbox ("linear");
	Checkbox quadraticSpring = new Checkbox ("quadratic");

	Panel vvRepulsionPanel = new Panel ();
	Label vvRepulsionLabel = new Label ("Vertex-Vertex Repulsion:");
	CheckboxGroup vertexVertexRepulsionLawGrp = new CheckboxGroup ();
	Checkbox vvInverse = new Checkbox ("inverse");
	Checkbox vvInverseSquare = new Checkbox ("inverse-square");
	Checkbox vvHybrid = new Checkbox ("hybrid");

	Panel barnesHutPanel = new Panel ();
	Checkbox useBarnesHut = new Checkbox ("Use Barnes-Hut for Vertex-Vertex Repulsion");
	Label thetaLabel = new Label ("Theta:");
	Slider theta = new Slider (Settings.barnesHutThetaMin, Settings.barnesHutThetaMax, Settings.barnesHutThetaDefault);

	Panel constraintPanel = new Panel ();
	Label constrainDimensions1 = new Label ("Constrain to");
	TextField projDimField = new TextField (" ");
	Label constrainDimensions2 = new Label ("Dimensions");
	Checkbox constrainToSphere = new Checkbox ("Constrain to Surface of Sphere");

	Panel okCancelPanel = new Panel ();
	Button ok = new Button ("OK");
	Button cancel = new Button ("CANCEL");
	
	public static class Settings {
	    public static double vertexWidthMin = 0;
	    public static double vertexWidthMax = 50;
	    public static double vertexWidthDefault = 10;
	    public double vertexWidth = vertexWidthDefault;

	    public static double vertexHeightMin = 0;
	    public static double vertexHeightMax = 50;
	    public static double vertexHeightDefault = 10;
	    public double vertexHeight = vertexHeightDefault;

	    public static double prefEdgeLengthMin = 0;
	    public static double prefEdgeLengthMax = 200;
	    public static double prefEdgeLengthDefault = 50;
	    public double prefEdgeLength = prefEdgeLengthDefault;

	    public ForceModel forceModel = null;
	    
	    public static boolean useVertexSizeDefault = true;
	    public boolean useVertexSize = useVertexSizeDefault;
	    
        public int projDim = 0;			// project dimensions constaint (0: dimensional no constraint)
        
        public ForceDirectedOptimizationProcedure optimizationProcedure = null;
        
        public SpringLaw attractionLaw = null;
		public VertexVertexRepulsionLaw repulsionLaw = null;
		public boolean useBarnesHut;

		public static double barnesHutThetaMin = 0;
	    public static double barnesHutThetaMax = 1;
	    public static double barnesHutThetaDefault = 0.9;
		public double barnesHutTheta;
	}

	public SettingsDlg (JiggleFrame p, int x, int y) {
		super (p, "Settings", true); parent = p;

		int w = 800, h = 600;
		setSize (w, h);
		setLocation (Math.max (0, x - w/2), Math.max (0, y - h/2));

		setLayout (new GridLayout (9, 1));

		edgeLengthLabel.setAlignment (Label.CENTER);
		edgeLengthPanel.add (edgeLengthLabel);
		edgeLengthPanel.add (edgeLength);
		add (edgeLengthPanel);

		vertexWidthLabel.setAlignment (Label.CENTER);
		vertexHeightLabel.setAlignment (Label.CENTER);
		useVertexSize.setState (Settings.useVertexSizeDefault);
		sizePanel.add (vertexWidthLabel);
		sizePanel.add (vertexWidth);
		sizePanel.add (vertexHeightLabel);
		sizePanel.add (vertexHeight);
		sizePanel.add (new Label ("          "));
		sizePanel.add (useVertexSize);
		add (sizePanel);

		optimizationProcedureLabel.setAlignment (Label.CENTER);
		optimizationProcedurePanel1.add (optimizationProcedureLabel);
		steepestDescent.setCheckboxGroup (optimizationProcedureGrp);
		conjugateGradients.setCheckboxGroup (optimizationProcedureGrp);
		conjugateGradients.setState (true);
		optimizationProcedurePanel1.add (steepestDescent);
		optimizationProcedurePanel1.add (conjugateGradients);
		add (optimizationProcedurePanel1);

		accuracyLabel.setAlignment (Label.CENTER);
		restartLabel.setAlignment (Label.CENTER);
		optimizationProcedurePanel2.add (accuracyLabel);
		optimizationProcedurePanel2.add (accuracyOfLineSearch);
		optimizationProcedurePanel2.add (restartLabel);
		optimizationProcedurePanel2.add (restartThreshold);
		add (optimizationProcedurePanel2);

		springLabel.setAlignment (Label.CENTER);
		springPanel.add (springLabel);
		linearSpring.setCheckboxGroup (springLawGrp);
		quadraticSpring.setCheckboxGroup (springLawGrp);
		quadraticSpring.setState (true);
		springPanel.add (linearSpring);
		springPanel.add (quadraticSpring);
		add (springPanel);

		vvRepulsionLabel.setAlignment (Label.CENTER);
		vvRepulsionPanel.add (vvRepulsionLabel);
		vvInverse.setCheckboxGroup (vertexVertexRepulsionLawGrp);
		vvInverseSquare.setCheckboxGroup (vertexVertexRepulsionLawGrp);
		vvHybrid.setCheckboxGroup (vertexVertexRepulsionLawGrp);
		vvInverseSquare.setState (true);
		vvRepulsionPanel.add (vvInverse);
		vvRepulsionPanel.add (vvInverseSquare);
		vvRepulsionPanel.add (vvHybrid);
		add (vvRepulsionPanel);

		thetaLabel.setAlignment (Label.CENTER);
		barnesHutPanel.add (useBarnesHut);
		barnesHutPanel.add (thetaLabel);
		barnesHutPanel.add (theta);
		add (barnesHutPanel);

		constraintPanel.add (constrainDimensions1);
		constraintPanel.add (projDimField);
		constraintPanel.add (constrainDimensions2);
		constraintPanel.add (constrainToSphere);
		add (constraintPanel);

		ok.addActionListener (new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                okClicked = true;
        		setVisible(false);
            }});
		cancel.addActionListener (new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                okClicked = false;
        		setVisible(false);
            }});
		okCancelPanel.add (ok);
		okCancelPanel.add (new Label ("          "));
		okCancelPanel.add (cancel);
		add (okCancelPanel);

	}
	
	public boolean okClicked = false;

	private int stringToInt(String s) {
        try {
            return new Integer(s.trim()).intValue();
        } catch (Exception exc) {
            return 0;
        }
    }

	public Settings getSettings () {
		Settings settings = new Settings();
		Graph g = parent.graph;

		settings.vertexWidth = vertexWidth.getValue ();
		settings.vertexHeight = vertexHeight.getValue ();
		settings.useVertexSize = useVertexSize.getState ();

		
		settings.prefEdgeLength = Math.max (1, edgeLength.getValue ());
		
		Checkbox selCB;
		
		selCB = springLawGrp.getSelectedCheckbox();
		if (selCB == linearSpring) {
		    settings.attractionLaw = new LinearSpringLaw (g, settings.prefEdgeLength);
		} else if (selCB == quadraticSpring) {						// default
		    settings.attractionLaw = new QuadraticSpringLaw (g, settings.prefEdgeLength);
		}
		
		selCB = vertexVertexRepulsionLawGrp.getSelectedCheckbox();
		if (selCB == vvInverse) {
		    settings.repulsionLaw = new InverseVertexVertexRepulsionLaw (g, settings.prefEdgeLength);
		} else if (selCB == vvInverseSquare) {						// default
		    settings.repulsionLaw = new InverseSquareVertexVertexRepulsionLaw (g, settings.prefEdgeLength);
		} else if (selCB == vvHybrid) {
		    settings.repulsionLaw = new HybridVertexVertexRepulsionLaw (g, settings.prefEdgeLength);
		}
		
		settings.useBarnesHut = useBarnesHut.getState();
		settings.barnesHutTheta = theta.getValue();
		if (settings.useBarnesHut) {
		    settings.repulsionLaw.setBarnesHutTheta (settings.barnesHutTheta);
		}

		ForceModel fm = new ForceModel (g);
		fm.addForceLaw (settings.attractionLaw);
		fm.addForceLaw (settings.repulsionLaw);

		
        settings.projDim = stringToInt (projDimField.getText ());
		if (settings.projDim > 0) {
			fm.addConstraint (new ProjectionConstraint (g, settings.projDim));
		}
		if (constrainToSphere.getState ()) {
			fm.addConstraint (new SurfaceOfSphereConstraint (g));
		}
		settings.forceModel = fm;

		
		ForceDirectedOptimizationProcedure opt = null;
		double acc = Math.max (accuracyOfLineSearch.getValue (), 0.00000001);
		double rt = restartThreshold.getValue ();
        selCB = optimizationProcedureGrp.getSelectedCheckbox();
		if (selCB == steepestDescent) {
			opt = new SteepestDescent (g, settings.forceModel, acc);
		} else if (selCB == conjugateGradients) {					// default
			opt = new ConjugateGradients (g, settings.forceModel, acc, rt);
		}
		
		settings.optimizationProcedure = opt;

		
		return settings;
	}

}
